<!doctype html>
<html>
	<head>
		<meta charset="UTF-8">
		<title> Js原生实现3d效果拖拽展示 </title>
	</head>
        <style type="text/css">
			body {
				background: #000;
			}
			/* perspective 属性定义 3D 元素距视图的距离，以像素计。该属性允许您改变 3D 元素查看 3D 元素的视图。当为元素定义 perspective 属性时，其子元素会获得透视效果，而不是元素本身。 */
			#perspective {
				perspective: 800px;
			}
			#wrap{
				position: relative;
				width: 120px;
				height: 180px;
				margin: auto;
				/* 设置3d环境 */
				transform: rotateX(-10deg);
				transform-style: preserve-3d;
			}
			#wrap img{
				position: absolute;
				width: 100%;
				height: 100%;
				cursor: pointer;
				border-radius: 4px;
				box-shadow: 0 0 1em pink;
				transform: rotateY(0deg) translateZ(0px);
				-webkit-box-reflect: below 10px -webkit-linear-gradient(top,rgba(0, 0, 0, 0) 40%,rgba(0, 0, 0, 0.5));
			}
		
			#wrap p {
				width: 1200px;
				height: 1200px;
				background:#fff;
				border-radius: 50%;
				position: absolute;
				top: 102%;
				left: 50%;
				margin-left: -600px;
				margin-top: -600px;
				transform: rotateX(90deg);
				background: -webkit-radial-gradient(center center, 600px 600px,rgba(242, 79, 242, 0.4),rgba(0,0,0,0));
			}
		</style>
<body>
	<div id="perspective">
		<div id="wrap">
			<img src="img/1.jpg"/>
			<img src="img/2.jpg"/>
			<img src="img/3.jpg"/>
			<img src="img/4.jpg"/>
			<img src="img/5.jpg"/>
			<img src="img/6.jpg"/>
			<img src="img/7.jpg"/>
			<img src="img/8.jpg"/>
			<img src="img/9.jpg"/>
			<img src="img/10.jpg"/>
			<img src="img/11.jpg"/>
			<p>Js原生实现3d效果拖拽展示</p>
		</div>
	</div>
<script>
	window.onload = function(){
		let roY = 0;
		let roX = -10; //给默认值
		let timer = null; // 给定时器设置默认值

		const oWrap = document.getElementById("wrap");
		const oImg = oWrap.getElementsByTagName("img");
		const oImgLength = oImg.length;
		const Deg = 360 / oImgLength;//获取度数
		let nowX, nowY, lastX, lastY, minusX, minusY;

		// 循环遍历每一个图片对象，添加相应的旋转度数与动画时间
		for(let i = 0; i < oImgLength; i++){
			oImg[i].style.transform = "rotateY(" + i * Deg + "deg) translateZ(350px)";
			oImg[i].style.transition = "transform 1s " + (oImgLength - 1 - i) * 0.2 + "s";
		};
		/**
		 *@Description 
		*@Return 动态的实现oWrap的位置居中.
		**/
		const mTop = () => {
			const wH = window.innerHeight;
			oWrap.style.marginTop = wH / 2 - 180 + "px";
		};

		mTop();
		window.onresize = mTop;
		/**
		 *@Description 
		 *@Return 拖拽 三个事件  按下 移动 抬起.
		**/
		document.onmousedown = (e) => {
			// 鼠标按下的时候，给前一点坐标赋值，避免第一次相减的时候出错
			const ev = e || window.event;
			lastX = ev.clientX;
			lastY = ev.clientY;
			
			// 鼠标移动
			this.onmousemove = (e) => {
				
				const moveE = e || window.event;
				// 拿到当前坐标的值
				nowX = moveE.clientX;
				nowY = moveE.clientY;
				
				clearInterval(timer); // 下一次拖动的时候清除上一次的定时

				minusX = nowX - lastX
				minusY = nowY - lastY
				
				roY += minusX * 0.2;
				roX -= minusY * 0.2;

				oWrap.style.transform = "rotateX(" + roX + "deg) rotateY(" + roY + "deg)";

				// 拿到上一个坐标的值
				lastX = nowX;
				lastY = nowY;

			};

			// 鼠标抬起
			this.onmouseup = () => {
				this.onmousemove = null;

				timer = setInterval(() => {
					minusX *= 0.95; // 让距离越来越小，乘以摩擦系数
					minusY *= 0.95;
					roY += minusX * 0.2;
					roX -= minusY * 0.2;

					oWrap.style.transform = "rotateX(" + roX + "deg) rotateY(" + roY + "deg)";
					
					// 考虑到会往反方向移动所以加绝对值
					if(Math.abs(minusX) < 0.5 && Math.abs(minusY) < 0.5){
						clearInterval(timer);
					}
				}, 13);

			};

			return false; // 阻止默认事件（全部选中与点击拖拽）
		};
	}
</script>
</body>
</html>
